package com.zp.business.impl.exam;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zp.base.api.RemoteSerialNumberUtils;
import com.zp.base.api.vo.ExamTypeVo;
import com.zp.business.entity.clinicOrder.ClinicOrders;
import com.zp.business.entity.clinicOrder.ClinicOrdersCost;
import com.zp.business.entity.clinicOrder.OutpTreatRec;
import com.zp.business.entity.clinicOrder.bo.ApplyItemBo;
import com.zp.business.entity.clinicOrder.bo.ClinicOrderParam;
import com.zp.business.entity.exam.ExamApply;
import com.zp.business.entity.exam.ExamItem;
import com.zp.business.entity.exam.bo.ExamApplyBo;
import com.zp.business.entity.exam.bo.ExamItemBo;
import com.zp.business.entity.exam.vo.ExamApplyVo;
import com.zp.business.entity.outpFees.OutpFeesDetail;
import com.zp.business.mapper.clinicOrder.ClinicOrdersCostMapper;
import com.zp.business.mapper.clinicOrder.ClinicOrdersMapper;
import com.zp.business.mapper.clinicOrder.OutpTreatRecMapper;
import com.zp.business.mapper.exam.ExamApplyMapper;
import com.zp.business.mapper.exam.ExamItemMapper;
import com.zp.business.mapper.outpFees.OutpFeesDetailMapper;
import com.zp.business.service.clinicOrder.IClinicOrdersService;
import com.zp.business.service.clinicOrder.IOutpTreatRecService;
import com.zp.business.service.exam.IExamApplyService;
import com.zp.business.service.exam.IExamItemService;
import com.zp.business.service.patient.IClinicMasterService;
import com.zp.common.core.constant.BaseConstants;
import com.zp.common.core.constant.CacheNames;
import com.zp.common.core.constant.UserConstants;
import com.zp.common.core.utils.DateUtils;
import com.zp.common.core.utils.StringUtils;
import com.zp.common.myBatis.core.page.PageQuery;
import com.zp.common.myBatis.core.page.TableDataInfo;
import com.zp.common.redis.utils.CacheUtils;
import com.zp.common.satoken.utils.LoginHelper;
import com.zp.system.api.entity.SysDept;
import com.zp.system.api.entity.SysUser;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 检查申请主Service业务层处理
 *
 * @author zhang peng
 * @ date 2024-01-05
 */
@RequiredArgsConstructor
@Service
public class ExamApplyServiceImpl implements IExamApplyService {

    private final ExamApplyMapper baseMapper;
    private final IExamItemService examItemService;
    private final ExamItemMapper examItemMapper;
    private final ClinicOrdersMapper clinicOrdersMapper;
    private final ClinicOrdersCostMapper clinicOrdersCostMapper;
    private final OutpFeesDetailMapper outpFeesDetailMapper;
    private final OutpTreatRecMapper outpTreatRecMapper;
    @DubboReference
    private RemoteSerialNumberUtils remoteSerialNumberUtils;
    private final IClinicOrdersService clinicOrdersService;
    private final IOutpTreatRecService outpTreatRecService;
    private final IClinicMasterService clinicMasterService;

    /**
     * 用户信息
     */
    static Map<String, SysUser> sysUserMap = CacheUtils.get(CacheNames.SYS_USER);
    static Map<String, SysDept> sysDeptMap = CacheUtils.get(CacheNames.SYS_DEPT);
    static Map<String, ExamTypeVo> examTypeVoMap = CacheUtils.get(CacheNames.EXAM_TYPE);

    /**
     * 查询检查申请主
     */
    @Override
    public ExamApplyVo queryById(String id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询检查申请主列表(分页)
     */
    @Override
    public TableDataInfo<ExamApplyVo> queryPageList(ExamApplyBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ExamApply> lqw = buildQueryWrapper(bo);
        Page<ExamApplyVo> result = new Page<>();
        if (StringUtils.equals(bo.getInoroutFlag(), BaseConstants.IS_CLINIC)) {
            result = baseMapper.selectVoPage(pageQuery.build(), bo);
        } else {

        }
        result.getRecords().forEach(item -> {
            item.setImplementDeptName(CollectionUtil.isNotEmpty(sysDeptMap) && StringUtils.isNotBlank(item.getImplementDept()) ? sysDeptMap.get(item.getImplementDept()).getDeptName() : "");
            item.setApplyDeptName(CollectionUtil.isNotEmpty(sysDeptMap) && StringUtils.isNotBlank(item.getApplyDept()) ? sysDeptMap.get(item.getApplyDept()).getDeptName() : "");
            item.setConfirmUserName(CollectionUtil.isNotEmpty(sysUserMap) && StringUtils.isNotBlank(item.getConfirmUser()) ? sysUserMap.get(item.getConfirmUser()).getNickName() : "");
            item.setApplyUserName(CollectionUtil.isNotEmpty(sysUserMap) && StringUtils.isNotBlank(item.getApplyUser()) ? sysUserMap.get(item.getApplyUser()).getNickName() : "");
            item.setCancelConfirmUserName(CollectionUtil.isNotEmpty(sysUserMap) && StringUtils.isNotBlank(item.getCancelConfirmUser()) ? sysUserMap.get(item.getCancelConfirmUser()).getNickName() : "");
            item.setExamTypeName(CollectionUtil.isNotEmpty(examTypeVoMap) && StringUtils.isNotBlank(item.getExamType()) ? examTypeVoMap.get(item.getExamType()).getName() : "");
            ExamItemBo examItemBo = new ExamItemBo();
            examItemBo.setOrgId(item.getOrgId());
            examItemBo.setApplyId(item.getId());
            examItemBo.setDelFlag("0");
            item.setExamItemVoList(examItemService.queryList(examItemBo));
        });
        return TableDataInfo.build(result);
    }

    /**
     * 查询检查申请主列表(不分页)
     */
    @Override
    public List<ExamApplyVo> queryList(ExamApplyBo bo) {
        LambdaQueryWrapper<ExamApply> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ExamApply> buildQueryWrapper(ExamApplyBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ExamApply> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getClinicId()), ExamApply::getClinicId, bo.getClinicId());
        lqw.eq(StringUtils.isNotBlank(bo.getApplyNo()), ExamApply::getApplyNo, bo.getApplyNo());
        lqw.eq(StringUtils.isNotBlank(bo.getPatientId()), ExamApply::getPatientId, bo.getPatientId());
        lqw.eq(StringUtils.isNotBlank(bo.getInoroutFlag()), ExamApply::getInoroutFlag, bo.getInoroutFlag());
        lqw.eq(StringUtils.isNotBlank(bo.getSymptom()), ExamApply::getSymptom, bo.getSymptom());
        lqw.eq(StringUtils.isNotBlank(bo.getSign()), ExamApply::getSign, bo.getSign());
        lqw.eq(StringUtils.isNotBlank(bo.getClinicalDiag()), ExamApply::getClinicalDiag, bo.getClinicalDiag());
        lqw.eq(StringUtils.isNotBlank(bo.getRelevantDiag()), ExamApply::getRelevantDiag, bo.getRelevantDiag());
        lqw.eq(StringUtils.isNotBlank(bo.getRelevantResult()), ExamApply::getRelevantResult, bo.getRelevantResult());
        lqw.eq(StringUtils.isNotBlank(bo.getConfirmUser()), ExamApply::getConfirmUser, bo.getConfirmUser());
        lqw.eq(StringUtils.isNotBlank(bo.getCancelConfirmUser()), ExamApply::getCancelConfirmUser, bo.getCancelConfirmUser());
        lqw.eq(StringUtils.isNotBlank(bo.getConfirmFlag()), ExamApply::getConfirmFlag, bo.getConfirmFlag());
        lqw.eq(bo.getConfirmDate() != null, ExamApply::getConfirmDate, bo.getConfirmDate());
        lqw.eq(StringUtils.isNotBlank(bo.getChargeFlag()), ExamApply::getChargeFlag, bo.getChargeFlag());
        lqw.eq(StringUtils.isNotBlank(bo.getApplyDept()), ExamApply::getApplyDept, bo.getApplyDept());
        lqw.eq(StringUtils.isNotBlank(bo.getImplementDept()), ExamApply::getImplementDept, bo.getImplementDept());
        lqw.eq(StringUtils.isNotBlank(bo.getIsUrgent()), ExamApply::getIsUrgent, bo.getIsUrgent());
        lqw.eq(StringUtils.isNotBlank(bo.getOrgId()), ExamApply::getOrgId, bo.getOrgId());
        lqw.eq(StringUtils.isNotBlank(bo.getRemarks()), ExamApply::getRemarks, bo.getRemarks());
        lqw.eq(StringUtils.isNotBlank(bo.getVisitId()), ExamApply::getVisitId, bo.getVisitId());
        lqw.eq(StringUtils.isNotBlank(bo.getClinicOrdersId()), ExamApply::getClinicOrdersId, bo.getClinicOrdersId());
        lqw.eq(StringUtils.isNotBlank(bo.getIsPhy()), ExamApply::getIsPhy, bo.getIsPhy());
        lqw.eq(StringUtils.isNotBlank(bo.getExamType()), ExamApply::getExamType, bo.getExamType());
        lqw.eq(StringUtils.isNotBlank(bo.getMainSuit()), ExamApply::getMainSuit, bo.getMainSuit());
        lqw.eq(StringUtils.isNotBlank(bo.getMatter()), ExamApply::getMatter, bo.getMatter());
        lqw.eq(StringUtils.isNotBlank(bo.getNotes()), ExamApply::getNotes, bo.getNotes());
        lqw.eq(StringUtils.isNotBlank(bo.getConfirmCancelFlag()), ExamApply::getConfirmCancelFlag, bo.getConfirmCancelFlag());
        lqw.eq(ExamApply::getDelFlag, "0");
        lqw.eq(StringUtils.isNotBlank(bo.getPacsFlag()), ExamApply::getPacsFlag, bo.getPacsFlag());
        lqw.eq(bo.getRealDate() != null, ExamApply::getRealDate, bo.getRealDate());
        lqw.orderByDesc(ExamApply::getCreateTime);
        return lqw;
    }

    /**
     * 新增检查申请主
     */
    @Override
    public Boolean insertByBo(ExamApplyBo bo) {
        ExamApply add = BeanUtil.toBean(bo, ExamApply.class);
        validEntityBeforeSave(add);
        add.initEntity();
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改检查申请主
     */
    @Override
    public Boolean updateByBo(ExamApplyBo bo) {
        ExamApply update = BeanUtil.toBean(bo, ExamApply.class);
        update.updateInfo();
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ExamApply entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除检查申请主
     */
    @Override
    @GlobalTransactional
    public int deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        for (String id : ids) {
            Map<String, Object> validateMap = validate(id);
            if ((Integer) validateMap.get("key") != 0) {
                return (Integer) validateMap.get("key");
            }
            ExamApplyVo examApplyVo = (ExamApplyVo) validateMap.get("examApplyVo");
            // 删除门诊处置治疗项目
            Boolean b = outpTreatRecService.deleteByBo(examApplyVo.getOrgId(), examApplyVo.getApplyNo());
            Boolean b1 = clinicOrdersService.deleteByBo(examApplyVo.getOrgId(), examApplyVo.getApplyNo());
            Boolean b2 = examItemService.deleteByBo(examApplyVo.getId());
            Boolean b3 = baseMapper.deleteById(examApplyVo.getId()) > 0;
            if (b && b1 && b2 && b3) {
                return 1;
            }
        }
        return 0;
    }


    /**
     * @param id 检查主表id
     * @throws
     * @description 校验删除的数据是否收费、或确认
     * @author zhp
     * @time 2024/2/28 下午4:10
     */

    private Map<String, Object> validate(String id) {
        ExamApplyVo examApplyVo = baseMapper.selectVoById(id);
        Map<String, Object> map = new HashMap<>();
        map.put("key", 0);
        map.put("examApplyVo", examApplyVo);
        if (ObjectUtil.isEmpty(examApplyVo)) {
            // 数据不存在
            map.put("key", 999);
        } else if (StringUtils.equals(examApplyVo.getConfirmFlag(), UserConstants.YES)) {
            // 已确认
            map.put("key", 998);
        } else if (StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.TWO)) {
            // 已收费
            map.put("key", 992);
        } else if (StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.THREE)) {
            // 申请退费
            map.put("key", 993);
        } else if (StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.FOUR)) {
            // 已退费
            map.put("key", 994);
        } else if (StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.FIVE)) {
            // 确认退费
            map.put("key", 995);
        } else if (StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX)) {
            // 科室确认退费中
            map.put("key", 996);
        }
        return map;
    }

    /**
     * @param bo 检查主表
     * @return boolean
     * @throws
     * @description 保存检查信息
     * @author zhp
     * @time 2024/1/25 下午9:05
     */
    @Override
    @GlobalTransactional
    public boolean saveExamApplyAndItem(ExamApplyBo bo) {
        // 诊疗项目id集合
        List<String> itemClinicIds = new ArrayList<>();
        ExamApply examApply = BeanUtil.toBean(bo, ExamApply.class);
        // 设置收费类型： 未收费 1
        examApply.setChargeFlag(BaseConstants.CHARGE_FLAG_DICT.ONE);
        // 设置确认类型： 未确认 1
        examApply.setConfirmFlag(BaseConstants.CONFIRM_FLAG.UNISSUED);
        // 设置检查单号
        examApply.setApplyNo(remoteSerialNumberUtils.generateExamNo(BaseConstants.IS_CLINIC, examApply.getOrgId()));
        examApply.initEntity();
        examApply.setIsPhy(UserConstants.NO);
        examApply.setRealDate(new Date());
        examApply.setPacsFlag(UserConstants.NO);
        examApply.setApplyUser(LoginHelper.getUserId());
        // 设置开单科室
        examApply.setApplyDept(LoginHelper.getDeptId());
        // 获取检查项目明细
        List<ExamItemBo> examItemBoList = bo.getExamItemBoList();
        // 检查主表信息保存
        boolean flag = baseMapper.insert(examApply) > 0;
        examItemBoList.forEach(examItem -> {
            examItem.setApplyId(examApply.getId());
            examItem.setCosts(examItem.getPrice().multiply(new BigDecimal(examItem.getNum())));
            examItem.setOrgId(examApply.getOrgId());
            examItem.setRealDate(examApply.getRealDate());
            examItem.setConfirmFlag(BaseConstants.CONFIRM_FLAG.UNISSUED);
        });
        List<ExamItem> examItemList = BeanUtil.copyToList(examItemBoList, ExamItem.class);
        if (flag) {
            List<ApplyItemBo> applyItemBoList = new ArrayList<>();
            // 保存检查项目明细
            List<ExamItem> examItems = examItemService.batchExamItem(examItemList);
            examItems.forEach(examItem -> {
                ApplyItemBo applyItemBo = new ApplyItemBo();
                applyItemBo.setApplyItemId(examItem.getId());
                applyItemBo.setClinicItemId(examItem.getClinicItemId());
                applyItemBo.setItemClass(BaseConstants.ITEM_CLASS.EXAM);
                applyItemBo.setNum(examItem.getNum());
                applyItemBoList.add(applyItemBo);
            });
            // 组织门诊待收费信息数据（clinicOrder、clinicOrderCost）等信息
            ClinicOrderParam clinicOrderParam = new ClinicOrderParam();
            clinicOrderParam.setApplyItemBoList(applyItemBoList);
//            clinicOrderParam.setItemClinicIds(itemClinicIds);
            // 设置诊疗项目类型
            clinicOrderParam.setItemClass(BaseConstants.ITEM_CLASS.EXAM);
            ExamApplyVo examApplyVo = BeanUtil.toBean(examApply, ExamApplyVo.class);
//            examApplyVo.setExamItemVoList(BeanUtil.copyToList(examItemList, ExamItemVo.class));
            clinicOrderParam.setOrgId(examApply.getOrgId());
            clinicOrderParam.setIsApply(UserConstants.YES);
            clinicOrderParam.setOrgId(examApply.getOrgId());
            clinicOrderParam.setIsApply(UserConstants.YES);
            clinicOrderParam.setDiagnosis(bo.getClinicalDiag());
            clinicOrderParam.setApplyNo(examApply.getApplyNo());
            clinicOrderParam.setApplyUser(examApply.getApplyUser());
            clinicOrderParam.setApplyDept(examApply.getApplyDept());
            clinicOrderParam.setImplementUser(examApply.getConfirmUser());
            clinicOrderParam.setImplementDept(examApply.getImplementDept());
            clinicOrderParam.setInoroutFlag(examApply.getInoroutFlag());
            clinicOrderParam.setClinicId(examApplyVo.getClinicId());
            clinicOrderParam.setPatientId(examApply.getPatientId());
            clinicOrderParam.setAbidance(1);
            clinicOrderParam.setNum(1);
            // 保存clinicOrder、clinicOrderCost信息
            ClinicOrders clinicOrders = clinicOrdersService.initClinicOrders(clinicOrderParam);
            // 更新主表中门诊医嘱id（clinic_orders_id）
            baseMapper.update(null, new LambdaUpdateWrapper<ExamApply>()
                    .set(ExamApply::getClinicOrdersId, clinicOrders.getId())
                    .eq(ExamApply::getId, examApply.getId()));
            // 新增处置治疗信息 start
            clinicOrderParam.setClinicOrdersId(clinicOrders.getId());
            clinicOrderParam.setGroupNo(clinicOrders.getGroupNo());
            outpTreatRecService.saveByBo(clinicOrderParam);
            // 新增处置治疗信息 end

            //修改接诊医生doctor_id
            if (StringUtils.equals(bo.getInoroutFlag(), BaseConstants.IS_CLINIC)) {
                clinicMasterService.updateDoctorId(bo.getClinicId(), bo.getIsUpdateDoctorId());
            }
        }
        return flag;
    }


    /**
     * 检查确认（取消确认），修改状态
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean examConfirmOk(ExamApplyBo bo) {
        List<ExamApplyVo> examApplyVos = baseMapper.selectVoList(Wrappers.<ExamApply>lambdaQuery().in(ExamApply::getId, bo.getIds()));
        examApplyVos.forEach(examApplyVo -> {
            baseMapper.update(null, Wrappers.<ExamApply>lambdaUpdate()
                    .set(ExamApply::getConfirmFlag, bo.getConfirmFlag())
                    .set(ExamApply::getConfirmUser, StringUtils.equals(bo.getConfirmFlag(), BaseConstants.CONFIRM_FLAG.ISSUED)
                            ? LoginHelper.getUserId() : "")
                    .set(ExamApply::getConfirmDate, StringUtils.equals(bo.getConfirmFlag(), BaseConstants.CONFIRM_FLAG.ISSUED) ?
                            DateUtils.getNowDate() : null)
                    .set(StringUtils.equals(bo.getConfirmFlag(), BaseConstants.CONFIRM_FLAG.UNISSUED),
                            ExamApply::getCancelConfirmUser, LoginHelper.getUserId())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            ExamApply::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(ExamApply::getId, examApplyVo.getId())
            );
            examItemMapper.update(null, Wrappers.<ExamItem>lambdaUpdate()
                    .set(ExamItem::getConfirmFlag, bo.getConfirmFlag())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            ExamItem::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(ExamItem::getApplyId, examApplyVo.getId())
            );
            clinicOrdersMapper.update(null, Wrappers.<ClinicOrders>lambdaUpdate()
                    .set(ClinicOrders::getConfirmFlag, bo.getConfirmFlag())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            ClinicOrders::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(ClinicOrders::getId, examApplyVo.getClinicOrdersId())
            );
            clinicOrdersCostMapper.update(null, Wrappers.<ClinicOrdersCost>lambdaUpdate()
                    .set(ClinicOrdersCost::getConfirmFlag, bo.getConfirmFlag())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            ClinicOrdersCost::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(ClinicOrdersCost::getOrdersId, examApplyVo.getClinicOrdersId())
            );
            outpTreatRecMapper.update(null, Wrappers.<OutpTreatRec>lambdaUpdate()
                    .set(OutpTreatRec::getConfirmFlag, bo.getConfirmFlag())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            OutpTreatRec::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(OutpTreatRec::getClinicOrdersId, examApplyVo.getClinicOrdersId())
            );
            outpFeesDetailMapper.update(null, Wrappers.<OutpFeesDetail>lambdaUpdate()
                    .set(OutpFeesDetail::getConfirmFlag, bo.getConfirmFlag())
                    .set(StringUtils.equals(examApplyVo.getChargeFlag(), BaseConstants.CHARGE_FLAG_DICT.SIX),
                            OutpFeesDetail::getChargeFlag, BaseConstants.CHARGE_FLAG_DICT.THREE)
                    .eq(OutpFeesDetail::getClinicOrderId, examApplyVo.getClinicOrdersId())
            );
        });
        return Boolean.TRUE;
    }
}
